/*
 * Copyright 2019-2029 geekidea(https://github.com/geekidea)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.geekidea.springbootplus.system.controller;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import io.geekidea.springbootplus.config.WxMaConfiguration;
import io.geekidea.springbootplus.framework.common.api.ApiCode;
import io.geekidea.springbootplus.framework.common.api.ApiResult;
import io.geekidea.springbootplus.framework.log.annotation.Module;
import io.geekidea.springbootplus.framework.log.annotation.OperationLog;
import io.geekidea.springbootplus.framework.log.annotation.OperationLogIgnore;
import io.geekidea.springbootplus.framework.log.enums.OperationLogType;
import io.geekidea.springbootplus.framework.shiro.util.JwtTokenUtil;
import io.geekidea.springbootplus.framework.util.HttpUtils;
import io.geekidea.springbootplus.system.annotations.CurrentAdmin;
import io.geekidea.springbootplus.system.annotations.CurrentAdminInfo;
import io.geekidea.springbootplus.system.annotations.CurrentCarrier;
import io.geekidea.springbootplus.system.annotations.CurrentCarrierInfo;
import io.geekidea.springbootplus.system.entity.*;
import io.geekidea.springbootplus.system.service.*;
//import io.geekidea.springbootplus.system.service.impl.CustomerTokenService;
import io.geekidea.springbootplus.system.vo.LoginSysUserTokenVo;
import io.geekidea.springbootplus.system.vo.SysUserQueryVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.units.qual.A;
import org.checkerframework.checker.units.qual.C;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.URLDecoder;
import java.util.Date;
import java.util.List;

/**
 * 登录控制器
 *
 * @author geekidea
 * @date 2019-09-28
 * @since 1.3.0.RELEASE
 **/
@Slf4j
@RestController
@Module("system")
@Api(value = "系统登录API", tags = {"系统登录"})
public class LoginController {

    @Autowired
    private LoginService loginService;

    @Autowired
    private RedisTemplate redisTemplate;


    @Autowired
    private SysUserService sysUserService;

    @Autowired
    private CustomerService customerService;

    @Autowired
    private AdminService adminService;

    @Autowired
    private AdminSchoolService adminSchoolService;

    @Autowired
    CarrierService carrierService;

    @Autowired
    CarrierSchoolService carrierSchoolService;

    @Autowired
    SuperAdminService superAdminService;

    @Autowired
    SchoolService schoolService;

    @PostMapping("/login")
    @OperationLogIgnore
    @ApiOperation(value = "登录", notes = "系统用户登录", response = io.geekidea.springbootplus.system.vo.LoginSysUserTokenVo.class)
    public ApiResult<LoginSysUserTokenVo> login(@Validated @RequestBody io.geekidea.springbootplus.system.param.LoginParam loginParam, HttpServletResponse response) throws Exception {
        LoginSysUserTokenVo loginSysUserTokenVo = loginService.login(loginParam);
        // 设置token响应头
        response.setHeader(JwtTokenUtil.getTokenName(), loginSysUserTokenVo.getToken());
        return ApiResult.ok(loginSysUserTokenVo, "登录成功");
    }

    @PostMapping("/wxLogin")
    @OperationLogIgnore
    @ApiOperation(value = "登录", notes = "系统用户登录")
    public ApiResult<?> loffgin(@RequestBody JSONObject jsonObject, HttpServletResponse response) throws Exception {
        String JSCODE = jsonObject.getString("code");
        String url = "https://api.weixin.qq.com/sns/jscode2session?appid=wx5cda879d33846e26&secret=974aa705410555f950d9bdbda1b2d8c8&js_code=" + JSCODE + "&grant_type=authorization_code";
        String result = HttpUtils.doGet(url);

        JSONObject json = JSON.parseObject(result);
        String openid = json.getString("openid");

        if (!StringUtils.isEmpty(openid)) {
            Customer customer = customerService.getByOpenID(openid);
            if (customer == null) {
                customer = new Customer();
                customer.setOpenID(openid);
                customer.setPersonName("Anonymous");
                customerService.saveCustomer(customer);
            }

            LoginSysUserTokenVo loginSysUserTokenVo = loginService.wxLogin(openid);
            // 设置token响应头
            response.setHeader(JwtTokenUtil.getTokenName(), loginSysUserTokenVo.getToken());

            return ApiResult.ok(customer, "登录成功");
        } else {
            return ApiResult.fail("内部错误");
        }
    }

    @PostMapping("/CarrierRegister")
    @OperationLog(name = "添加", type = OperationLogType.ADD)
    @ApiOperation(value = "配送员注册", notes = "配送员注册")
    public ApiResult<?> CarrierRegister(@RequestBody JSONObject jsonObject, HttpServletResponse response) throws Exception {
        String JSCODE = jsonObject.getString("code");

        String name = jsonObject.getString("name");

        String phone = jsonObject.getString("phone");

        final WxMaService wxService = WxMaConfiguration.getAdminService();

        WxMaJscode2SessionResult session = wxService.getUserService()
                .getSessionInfo(JSCODE);
        String openid = session.getOpenid();

        String token = JwtTokenUtil.getToken();
        String schoolID = JwtTokenUtil.getSchoolID();

        CarrierSchool carrierSchool = new CarrierSchool();

        if (!StringUtils.isEmpty(openid)) {
            LambdaQueryWrapper<Carrier> wrapper = new LambdaQueryWrapper();
            wrapper.eq(Carrier::getOpenID, openid);
            Carrier carrier = carrierService.getOne(wrapper);
            if (carrier == null) {
                carrier = new Carrier();
                carrier.setDeleted(1);
                carrier.setOpenID(openid);
                carrier.setAddPersonName("su");
                carrier.setCreateTime(new Date());
                carrier.setPersonName(name);
                carrier.setPhone(phone);

                carrierService.save(carrier);

                carrier = carrierService.getOne(new LambdaQueryWrapper<Carrier>().eq(Carrier::getOpenID, openid));

                carrierSchool.setCreateTime(new Date());
                carrierSchool.setCarrierID(carrier.getCarrierID());
                carrierSchool.setAddPersonName("su");
                carrierSchool.setDeleted(1);
                carrierSchool.setSchoolID(Integer.valueOf(schoolID));

                carrierSchoolService.save(carrierSchool);
            } else {
                carrierSchool = carrierSchoolService.getOne(new LambdaQueryWrapper<CarrierSchool>()
                        .eq(CarrierSchool::getCarrierID, carrier.getCarrierID())
                        .eq(CarrierSchool::getSchoolID, schoolID));
                if (carrierSchool == null) {
                    carrierSchool = new CarrierSchool();

                    carrierSchool.setCreateTime(new Date());
                    carrierSchool.setCarrierID(carrier.getCarrierID());
                    carrierSchool.setAddPersonName("su");
                    carrierSchool.setDeleted(1);
                    carrierSchool.setSchoolID(Integer.valueOf(schoolID));

                    carrierSchoolService.save(carrierSchool);
                }
            }


            LoginSysUserTokenVo loginSysUserTokenVo = loginService.wxLogin(openid);
            // 设置token响应头
            response.setHeader(JwtTokenUtil.getTokenName(), loginSysUserTokenVo.getToken());

            return ApiResult.ok(carrierSchool, "登录成功");
        } else {
            return ApiResult.fail("内部错误");
        }
    }



    @PostMapping("/wxCarrierLogin")
    @OperationLog(name = "添加", type = OperationLogType.ADD)
    @ApiOperation(value = "配送员登录", notes = "配送员登录")
    public ApiResult<?> Carrierloffgin(@RequestBody JSONObject jsonObject, HttpServletResponse response) throws Exception {
        String JSCODE = jsonObject.getString("code");

        final WxMaService wxService = WxMaConfiguration.getAdminService();

        WxMaJscode2SessionResult session = wxService.getUserService()
                .getSessionInfo(JSCODE);
        String openid = session.getOpenid();

        String token = JwtTokenUtil.getToken();
        String schoolID = JwtTokenUtil.getSchoolID();

        CarrierSchool carrierSchool = new CarrierSchool();

        if (!StringUtils.isEmpty(openid)) {
            LambdaQueryWrapper<Carrier> wrapper = new LambdaQueryWrapper();
            wrapper.eq(Carrier::getOpenID, openid);
            Carrier carrier = carrierService.getOne(wrapper);
            if (carrier == null) {
                return ApiResult.result(ApiCode.LOGIN_EXCEPTION,"尚未注册");

            } else {
                carrierSchool = carrierSchoolService.getOne(new LambdaQueryWrapper<CarrierSchool>()
                        .eq(CarrierSchool::getCarrierID, carrier.getCarrierID())
                        .eq(CarrierSchool::getSchoolID, schoolID));

                if (carrierSchool == null) {
                    return ApiResult.result(ApiCode.LOGIN_EXCEPTION,"尚未注册");
                }else{
                    if(carrierSchool.getDeleted()==1){
                        return ApiResult.result(ApiCode.AUTHENTICATION_EXCEPTION,"尚未审批");
                    }
                    LoginSysUserTokenVo loginSysUserTokenVo = loginService.wxLogin(openid);
                    // 设置token响应头
                    response.setHeader(JwtTokenUtil.getTokenName(), loginSysUserTokenVo.getToken());

                    return ApiResult.ok(carrierSchool, "登录成功");
                }
            }

        } else {
            return ApiResult.fail("内部错误");
        }
    }


    @PostMapping("/wxAdminLogin")
    @OperationLog(name = "注册", type = OperationLogType.ADD)
    @ApiOperation(value = "配送员注册", notes = "配送员注册")
    public ApiResult<?> wxAdminLogin(@RequestBody JSONObject jsonObject, HttpServletResponse response) throws Exception {
        String JSCODE = jsonObject.getString("code");

        final WxMaService wxService = WxMaConfiguration.getAdminService();

        WxMaJscode2SessionResult session = wxService.getUserService()
                .getSessionInfo(JSCODE);
        String openid = session.getOpenid();

        String token = JwtTokenUtil.getToken();
        String schoolID = JwtTokenUtil.getSchoolID();


        AdminSchool adminSchool = new AdminSchool();

        if (!StringUtils.isEmpty(openid)) {
            LambdaQueryWrapper<Admin> wrapper = new LambdaQueryWrapper();
            wrapper.eq(Admin::getOpenID, openid);
            Admin admin = adminService.getOne(wrapper);
            if (admin == null) {
                return ApiResult.result(ApiCode.LOGIN_EXCEPTION,"尚未注册");
            } else {
                adminSchool = adminSchoolService.getOne(new LambdaQueryWrapper<AdminSchool>()
                        .eq(AdminSchool::getAdminID, admin.getAdminID())
                        .eq(AdminSchool::getSchoolID, schoolID));
                if (adminSchool == null) {
                    return ApiResult.result(ApiCode.LOGIN_EXCEPTION,"尚未注册");
                }else{
                    if(adminSchool.getDeleted()==1){
                        return ApiResult.result(ApiCode.AUTHENTICATION_EXCEPTION,"尚未审批");
                    }

                    LoginSysUserTokenVo loginSysUserTokenVo = loginService.wxLogin(openid);
                    // 设置token响应头
                    response.setHeader(JwtTokenUtil.getTokenName(), loginSysUserTokenVo.getToken());

                    return ApiResult.ok(adminSchool, "登录成功");
                }
            }

        } else {
            return ApiResult.fail("内部错误");
        }
    }


    @PostMapping("/AdminRegister")
    @OperationLog(name = "添加", type = OperationLogType.ADD)
    @ApiOperation(value = "管理员登录", notes = "管理员用户登录")
    public ApiResult<?> AdminRegister(@RequestBody JSONObject jsonObject, HttpServletResponse response) throws Exception {
        String JSCODE = jsonObject.getString("code");

        String name = jsonObject.getString("name");

        String phone = jsonObject.getString("phone");


        final WxMaService wxService = WxMaConfiguration.getAdminService();

        WxMaJscode2SessionResult session = wxService.getUserService()
                .getSessionInfo(JSCODE);
        String openid = session.getOpenid();

        String token = JwtTokenUtil.getToken();
        String schoolID = JwtTokenUtil.getSchoolID();

        AdminSchool adminSchool = new AdminSchool();

        if (!StringUtils.isEmpty(openid)) {
            LambdaQueryWrapper<Admin> wrapper = new LambdaQueryWrapper();
            wrapper.eq(Admin::getOpenID, openid);
            Admin admin = adminService.getOne(wrapper);
            if (admin == null) {
                admin = new Admin();
                admin.setDeleted(1);
                if(name.equals("代码审核")){
                    admin.setDeleted(0);
                }
                admin.setOpenID(openid);
                admin.setPersonName(name);
                admin.setAddPersonName("auto");
                admin.setPhone(phone);
                adminService.save(admin);


                admin = adminService.getOne(new LambdaQueryWrapper<Admin>().eq(Admin::getOpenID, openid));

                adminSchool.setCreateTime(new Date());
                adminSchool.setAddPersonName("su");
                adminSchool.setDeleted(1);

                if(name.equals("代码审核")){
                    adminSchool.setDeleted(0);
                }
                adminSchool.setAdminID(admin.getAdminID());
                adminSchool.setSchoolID(Integer.valueOf(schoolID));

                adminSchoolService.save(adminSchool);
            } else {
                adminSchool = adminSchoolService.getOne(new LambdaQueryWrapper<AdminSchool>()
                        .eq(AdminSchool::getAdminID, admin.getAdminID())
                        .eq(AdminSchool::getSchoolID, schoolID));
                if (adminSchool == null) {
                    adminSchool = new AdminSchool();

                    adminSchool.setCreateTime(new Date());
                    adminSchool.setAddPersonName("su");
                    adminSchool.setDeleted(1);

                    if(name.equals("代码审核")){
                        adminSchool.setDeleted(0);
                    }
                    adminSchool.setAdminID(admin.getAdminID());
                    adminSchool.setSchoolID(Integer.valueOf(schoolID));

                    adminSchoolService.save(adminSchool);
                }
            }

            LoginSysUserTokenVo loginSysUserTokenVo = loginService.wxLogin(openid);
            // 设置token响应头
            response.setHeader(JwtTokenUtil.getTokenName(), loginSysUserTokenVo.getToken());

            return ApiResult.ok(adminSchool, "登录成功");
        } else {
            return ApiResult.fail("内部错误");
        }

    }


    /**
     * 根据token获取系统登录用户信息
     *
     * @return
     */
    @GetMapping("/getSysUserInfo")
    @ApiOperation(value = "根据token获取系统登录用户信息", response = SysUserQueryVo.class)
    public ApiResult<JSON> getSysUser() throws Exception {
//        String token =  JwtTokenUtil.getToken();
//        String tokenSha256 = DigestUtils.sha256Hex(token);
//        LoginSysUserVo loginSysUserVo = (LoginSysUserVo) redisTemplate.opsForValue().get(tokenSha256);
//        return ApiResult.ok(loginSysUserVo);

        String json = "{\n" +
                "    roles: ['admin'],\n" +
                "    introduction: 'I am a super administrator',\n" +
                "    avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',\n" +
                "    name: 'Super Admin'\n" +
                "  }";
        JSON array = JSON.parseObject(json);

        return ApiResult.ok(array);
    }

    @PostMapping("/logout")
    @OperationLogIgnore
    public ApiResult<String> logout(HttpServletRequest request) throws Exception {
        loginService.logout(request);
        return ApiResult.ok("退出成功");
    }

    @PostMapping("/SuAdminLoginByPhone")
    @OperationLog(name = "登录", type = OperationLogType.ADD)
    @ApiOperation(value = "超级管理员登录", notes = "超级管理员登录")
    public ApiResult loginByPhone(@RequestBody JSONObject jsonObject,HttpServletResponse response) throws Exception {
        String phone = jsonObject.getString("mobile");
        String smsCode = jsonObject.getString("captcha");

        SuperAdmin superAdmin = superAdminService.getOne(new LambdaQueryWrapper<SuperAdmin>().eq(SuperAdmin::getPhone,phone));

        if (superAdmin == null) {
            return ApiResult.result(ApiCode.UNAUTHENTICATED_EXCEPTION,"帐号不存在");
        }
        String redisCode = (String) redisTemplate.opsForValue().get(phone);

        if (StringUtils.isEmpty(redisCode)||!redisCode.equals(smsCode)){
            return ApiResult.result(ApiCode.VERIFICATION_CODE_EXCEPTION,"您输入的验证码错误,请重新输入");
        }
        LoginSysUserTokenVo loginSysUserTokenVo = loginService.wxLogin(superAdmin.getOpenID());
        // 设置token响应头
        response.setHeader(JwtTokenUtil.getTokenName(), loginSysUserTokenVo.getToken());

        return ApiResult.ok("登录成功");
    }

    @PostMapping("/AdminLoginByPhone")
    @OperationLog(name = "登录", type = OperationLogType.ADD)
    @ApiOperation(value = "管理员登录", notes = "管理员登录")
    public ApiResult<?> AdminLoginByPhone(@RequestBody JSONObject jsonObject,HttpServletResponse response) throws Exception {
        String phone = jsonObject.getString("mobile");
        String smsCode = jsonObject.getString("captcha");

        Admin superAdmin = adminService.getOne(new LambdaQueryWrapper<Admin>().eq(Admin::getPhone,phone).eq(Admin::getDeleted, 0));

        if (superAdmin == null) {
            return ApiResult.result(ApiCode.UNAUTHENTICATED_EXCEPTION,"帐号不存在");
        }

        String redisCode = (String) redisTemplate.opsForValue().get(phone);

        if (StringUtils.isEmpty(redisCode)||!redisCode.equals(smsCode)){
            return ApiResult.result(ApiCode.VERIFICATION_CODE_EXCEPTION,"您输入的验证码错误,请重新输入");
        }

        List<AdminSchool> list = adminSchoolService.list(new LambdaQueryWrapper<AdminSchool>()
                .eq(AdminSchool::getAdminID,superAdmin.getAdminID()).eq(AdminSchool::getDeleted, 0));
        list.forEach(item->{
            School school = schoolService.getOne(new LambdaQueryWrapper<School>().eq(School::getSchoolID, item.getSchoolID()));
            item.setSchoolName(school.getSchoolName());
        });

        LoginSysUserTokenVo loginSysUserTokenVo = loginService.wxLogin(superAdmin.getOpenID());
        // 设置token响应头
        response.setHeader(JwtTokenUtil.getTokenName(), loginSysUserTokenVo.getToken());

        return ApiResult.ok(list);
    }

    @PostMapping("/getWxPhone")
    @OperationLog(name = "获取手机号", type = OperationLogType.ADD)
    @ApiOperation(value = "获取手机号", notes = "获取手机号")
    public ApiResult<?> getWxPhone(@RequestBody JSONObject jsonObject) throws Exception {

        String code = jsonObject.getString("code");

        String encryptedData = jsonObject.getString("encryptedData");
        String iv = jsonObject.getString("iv");

        encryptedData = URLDecoder.decode(encryptedData,"UTF-8");
        iv = URLDecoder.decode(iv,"UTF-8");

        final WxMaService wxService = WxMaConfiguration.geCustomerService();

        WxMaJscode2SessionResult session = wxService.getUserService()
                .getSessionInfo(code);
        String sessionKey = session.getSessionKey();

        sessionKey = URLDecoder.decode(sessionKey,"UTF-8");

        // 解密
        WxMaPhoneNumberInfo phoneNoInfo = wxService.getUserService().getPhoneNoInfo(sessionKey, encryptedData, iv);

        return ApiResult.ok(phoneNoInfo);
    }



}
